package hck;

import java.awt.Color;
import robocode.HitByBulletEvent;
import robocode.HitRobotEvent;
import robocode.Robot;
import robocode.RobotDeathEvent;
import robocode.Rules;
import robocode.ScannedRobotEvent;
import robocode.WinEvent;

/**
 * StoogeBot: Ram and Gun type competitive robot. 
 * Will try to take out the competition.
 * 
 * @author Harry Kwan
 * @version 1.0
 */
public class StoogeBot extends Robot {

  // tank, field and enemy variables
  private static final double minBulletPower = Rules.MIN_BULLET_POWER;
  private static final double maxBulletPower = Rules.MAX_BULLET_POWER;
  private double fieldSizeX;
  private double fieldSizeY;
  private double maxDistance;
  private double gunBearing = 0;
  private double direction;
  private double targetLife;
  private String target = null;
  private int time = 0;

  /**
   * Sets up robot settings and actions.
   */
  public void run() {
    // field calculations
    fieldSizeX = getBattleFieldWidth();
    fieldSizeY = getBattleFieldHeight();
    this.maxDistance = Math.sqrt(Math.pow(this.fieldSizeX, 2) 
        + Math.pow(this.fieldSizeY, 2));

    // set robot colors
    this.setAllColors(Color.BLACK);
    // this.setBodyColor(Color.);
    // this.setGunColor(Color.);
    // this.setRadarColor(Color.);
    // this.setBulletColor(Color.);
    // this.setScanColor(Color.);

    // set freedom of movement for tank components
    this.setAdjustRadarForGunTurn(true);
    this.setAdjustRadarForRobotTurn(true);
    // this.setAdjustGunForRobotTurn(true);

    // always scanning for enemy robots
    // if enabled, will not reach remaining code below
    // this.turnRadarRight(Double.POSITIVE_INFINITY);

    for (;;) {
      // increments idle time
      this.time++;

      // scan for enemies before moving
      this.turnRadarRight(360);

      // look for enemies if non are scanned for 3 turns
      if (this.time > 2) {
        // resets target, has not been seen
        this.setTarget(null);
        this.targetLife = 200;

        // random move of 10 to 100 pixels
        this.ahead(randomDistance());
        this.turnRadarRight(360 + 30);

        // random turn of robot
        this.direction = Math.random() * 10;
        if (this.direction <= 5) {
          turnRight(90);
        }
        else {
          turnLeft(90);
        }

      }
    }
  }

  /**
   * Picks a target and fires.
   * 
   * @param sre Event that occurs when another robot is scanned.
   */
  public void onScannedRobot(ScannedRobotEvent sre) {
    // resets time idle to zero
    this.time = 0;

    // sets the first scanned enemy as the target
    if (this.getTarget() == null) {
      this.setTarget(sre.getName());
    }

    this.determineTarget(sre.getName(), sre.getEnergy());

    if (sre.getName().equals(this.getTarget())) {
      // shoot enemy
      this.turnGunRight(sre.getBearing() - this.gunBearing);
      this.gunBearing = sre.getBearing();
      // 1-distance/maxDistance proportionality equation-->Kevin Leong's Boom03
      this.fireBullet((1 - (sre.getDistance() / this.maxDistance)) 
          * StoogeBot.maxBulletPower);

      // ram into enemy
      this.turnRight(sre.getBearing());
      this.ahead(sre.getDistance());
    }
    else {
      // target not found, fire at sighted enemy anyways
      this.turnGunRight(sre.getBearing() - this.gunBearing);
      this.gunBearing = sre.getBearing();
      this.fireBullet(minBulletPower + 1);

      // reset target find weakest target
      this.targetLife = 200;
    }
  }

  /**
   * Try pick the weakest enemy robot as the target.
   * 
   * @param targetName Name of possible target change.
   * @param targetLife Life or energy of possible target change.
   */
  public void determineTarget(String targetName, double targetLife) {
    if ((this.fieldSizeX >= 2000) && 
        (this.fieldSizeY >= 2000) && 
        !(targetName.equals(this.getTarget())) && 
        (targetLife < this.targetLife)) {
      this.targetLife = targetLife;
      this.setTarget(targetName);
    }
  }

  /**
   * Tries to move away from future bullets coming from the same direction. Note: Not ideal for
   * small battles.
   * 
   * @param hbbe Event that occurs when robot gets hit by a bullet.
   */
  public void onHitByBullet(HitByBulletEvent hbbe) {
    this.turnRight(90 - hbbe.getBearing());
    this.turnLeft(90);
    this.back(100);
  }

  /**
   * Turns gun on other robot and fires full power.
   * 
   * @param hre Event that occurs when robot collides with another robot.
   */
  public void onHitRobot(HitRobotEvent hre) {
    // turn gun and fire
    this.turnGunRight(hre.getBearing() - this.gunBearing);
    this.gunBearing = hre.getBearing();
    this.fireBullet(StoogeBot.maxBulletPower);
  }

  /**
   * Removes dead robot as target (if it was the target).
   * 
   * @param rde Event that occurs when another robot is destroyed.
   */
  public void onRobotDeath(RobotDeathEvent rde) {
    if (this.getTarget().equals(rde.getName())) {
      this.setTarget(null);
    }
  }

  /**
   * Victory dance.
   * 
   * @param we Event that occurs when robot wins.
   */
  public void onWin(WinEvent we) {
    this.setAdjustGunForRobotTurn(true);
    this.setAdjustRadarForGunTurn(true);
    this.setAdjustRadarForRobotTurn(true);
    this.turnLeft(360);
    for (double i = 0.1; i < StoogeBot.maxBulletPower; i += 0.1) {
      this.fireBullet(i);
    }
  }

  /**
   * Sets robot's current target.
   * 
   * @param target The target to set.
   */
  public void setTarget(String target) {
    this.target = target;
  }

  /**
   * Returns robot's current target.
   * 
   * @return The target.
   */
  public String getTarget() {
    return this.target;
  }

  /**
   * Returns a random distance based on the field size or radar radius.
   * 
   * @return Random distance value.
   */
  public double randomDistance() {
    // if max distance in the field is bigger than radius
    // bullets will be under-powered, so set max to radar radius
    if (this.maxDistance > Rules.RADAR_SCAN_RADIUS) {
      this.maxDistance = Rules.RADAR_SCAN_RADIUS;
    }
    // returns 0 to 90 percent of maxDistance
    return (Math.random() * this.maxDistance);
  }

  /**
   * @return Engery of the Robot
   */
  public double getHealth() {
    return this.getEnergy();
  }
}
